#include "FileHandler.h"
#include "FileBlock.h"
#include "tcpmanager.h"
#include "filemanager.h"
#include "Sington.h"

#include <QThread>
#include <QElapsedTimer>

struct FileRecord {
    FileHeader header;
    QSharedPointer<QFile> file;
    volatile qint64 recvSize;
};

static QHash<decltype(TcpBlock::magicNumber), FileRecord> fileHash;
static QHash<decltype(TcpBlock::magicNumber), QElapsedTimer> recvTimer;
static QHash<decltype(TcpBlock::magicNumber), qint64> lastRecv;
static QHash<decltype(TcpBlock::magicNumber), qint64> lastSend;
static QHash<TransferSocket *, qint32> socketBind;
static QHash<QSharedPointer<QFile>, qint64> fileMapMagic;


FileHandler::FileHandler(QObject *parent) :
    QObject(parent)
{
    using namespace std::placeholders;
    qDebug() << "FileHandler run in" << thread();
    TcpManager* tcpManager = TcpManager::instance();
    /* 注册回调函数到TcpManager里面 */
    tcpManager->registerFunctor(FILE_HEADER, std::bind(&FileHandler::onRecvNewFile, this, _1, _2));
    tcpManager->registerFunctor(FILE_BODY, std::bind(&FileHandler::onNewFileBody, this, _1, _2));
}


void FileHandler::sendFile(QUrl url)
{
    TcpManager* tcpManager = TcpManager::instance();
    FileManager *fileManager = FileManager::instance();
    auto file = fileManager->openForRead(url);
    auto sockets = tcpManager->getSockets();
//    for (auto socket = sockets.begin(); socket != sockets.end(); ++socket) {
//        (*socket)->sendFile(file);
//        connect((*socket).get(), SIGNAL(sendFileComplete(QSharedPointer<QFile>)),
//                this, SLOT(onSendFileComplete(QSharedPointer<QFile>)));

//        // 连接发送进度
//        connect((*socket).get(), SIGNAL(writingFileBar(QSharedPointer<QFile>, qint64, qint64)),
//                this, SLOT(onSendBarNotice(QSharedPointer<QFile>, qint64, qint64)));
//    }
    auto socket = tcpManager->getSocket("test");
    qDebug() <<"==========="<< (socket == nullptr);
    if (!socketBind.count(socket.get())) {
        connect(socket.get(), SIGNAL(sendFileComplete(QSharedPointer<QFile>)),
                this, SLOT(onSendFileComplete(QSharedPointer<QFile>)));
        // 连接发送进度
        connect(socket.get(), SIGNAL(writingFileBar(QSharedPointer<QFile>, qint64, qint64)),
                this, SLOT(onSendBarNotice(QSharedPointer<QFile>, qint64, qint64)));
        socketBind[socket.get()] = 1;
    }
    socket->sendFile(file);
}

FileHandler *FileHandler::instance()
{
    return Sington<FileHandler>::getInstance();
}

//接收
// 测试使用
static QElapsedTimer timer;
static qint64 offset = 0;
// 测试使用
void FileHandler::onRecvNewFile(qint64 magic, QByteArray data)
{
    timer.start();
    offset = 0;

    FileRecord record;
    FileHeader header = FileHeader::fromByteArray(data);
    FileManager *fileManager = FileManager::instance();
    qDebug() << "Recv new file" << header.fileName << "magic" << magic;
    auto file = fileManager->openForWrite(fileManager->fileRecvPath() + "\\" + header.fileName);

    QElapsedTimer timer;
    recvTimer[magic] = timer;

    recvTimer[magic].start();
    lastRecv[magic] = 0;

    record.header   = header;
    record.file     = file;
    record.recvSize = 0;

    // 获取文件名信号
    emit firstFileType(magic, record.header.fileName, 0);

    fileHash[magic] = record;
}

//接收
void FileHandler::onNewFileBody(qint64 magic, QByteArray data)
{
    FileRecord& record = fileHash[magic];
    auto file = record.file;
    qint64 size = data.size();
    record.recvSize += size;

    if (recvTimer.count(magic) && recvTimer[magic].elapsed() >= 1000) {
        recvTimer[magic].restart();

        qint64 last = lastRecv[magic];
        qint64 recvDetal = record.recvSize - last;
        lastRecv[magic] = record.recvSize;

        emit updateRate(magic, recvDetal, 0);

        double ratio = record.recvSize * 100.0 / record.header.fileSize;

        emit updateRatio(magic, ratio, 0);
        qDebug() << "===================" << recvDetal * 1.0 /1024 / 1024;

    }


    file->write(std::move(data));
    file->waitForBytesWritten(30000);
    if (record.recvSize == record.header.fileSize) {
        // 文件传输完成
        auto it = fileHash.find(magic); // 从哈希表中清除
        fileHash.erase(it);

        recvTimer[magic].invalidate();
        //文件接收完成，这里发送一个信号过去，从列表里面删除

        qDebug() << "recvComplete=========>>" << magic;
        recvTimer.erase(recvTimer.find(magic));

        lastRecv.erase(lastRecv.find(magic));
        qDebug() << "File" << record.header.fileName << "receivce completed.";
        file->close();  // 关闭文件
    }

    // 测试使用
    if (timer.elapsed() >= 1000 || record.recvSize == record.header.fileSize) {
        timer.restart();
        qDebug() << "Recv speed" << (record.recvSize - offset) / 1024 / 1024 << "MB/s";
        offset = record.recvSize;
    }
    // 测试使用
}

void FileHandler::cancleFileDialogPage()
{
    emit fileDialogPageCancle();
}

//发送完成
void FileHandler::onSendFileComplete(QSharedPointer<QFile> file)
{
    file->close();

    if (fileMapMagic.count(file)) {
        //文件发送完成后，发送信号将其从页面list中清楚掉
        emit deleteFileList(fileMapMagic[file]);
        qDebug() << "fileComplete=========>>" << fileMapMagic[file];
        //
        lastSend.erase(lastSend.find(fileMapMagic[file]));
        fileMapMagic.erase(fileMapMagic.find(file));
    }
}

// 发送，一秒会触发一次
void FileHandler::onSendBarNotice(QSharedPointer<QFile> file, qint64 magic, qint64 offset)
{
    if (!lastSend.count(magic)) {
        lastSend[magic] = offset; // 0
        fileMapMagic[file] = magic;
        // 新发送文件信号
        emit firstFileType(magic, file->fileName(), 1);
    }
    qDebug() << "========== " << offset << " == " << lastSend[magic];
    qint64 rate = offset - lastSend[magic];
    lastSend[magic] = offset;

    emit updateRate(magic, rate, 1);
    qDebug() << "Send speed" << rate / 1024 / 1024 << "MB/S";
    double ratio = offset * 100.0 / (file->size());

    emit updateRatio(magic, ratio, 1);
}

bool FileHandler::runInLoop() const
{
    return QThread::currentThread() == thread();
}
